Skip to main content

Axir ERC20Paymaster

The ERC20Paymaster is an ERC-4337 compliant Paymaster contract that allows sponsoring gas fees in exchange for ERC-20 tokens. It supports various payment modes, including user-paid transactions with or without limits, and transactions with guarantors.

Overview​

The ERC20Paymaster contract enables users to pay for transaction fees using ERC-20 tokens instead of the native cryptocurrency (e.g., ETH). It uses oracles to fetch the latest token prices and supports standard and up-rebasing ERC-20 tokens.

Key features:

  • Support for multiple payment modes
  • Dynamic pricing based on oracle data
  • Refund of excess tokens
  • Configurable price markup

Constructor​

constructor(
IERC20Metadata _token,
IEntryPoint _entryPoint,
IOracle _tokenOracle,
IOracle _nativeAssetOracle,
uint32 _stalenessThreshold,
address _owner,
uint32 _priceMarkupLimit,
uint32 _priceMarkup,
uint256 _refundPostOpCost,
uint256 _refundPostOpCostWithGuarantor
)

Initializes the ERC20Paymaster contract with the following parameters:

  • _token: The ERC20 token used for transaction fee payments
  • _entryPoint: The ERC-4337 EntryPoint contract
  • _tokenOracle: Oracle contract for token to USD prices
  • _nativeAssetOracle: Oracle contract for native asset (ETH, Matic, etc.) to USD prices
  • _stalenessThreshold: Time in seconds after which an oracle result is considered stale
  • _owner: Address to be set as the contract owner
  • _priceMarkupLimit: Maximum allowed price markup percentage (1e6 = 100%)
  • _priceMarkup: Initial price markup percentage (1e6 = 100%)
  • _refundPostOpCost: Estimated gas cost for token refunds
  • _refundPostOpCostWithGuarantor: Estimated gas cost for token refunds with a guarantor

Payment Modes​

The paymaster supports four modes:

  1. User pays, no limit
  2. User pays, with a limit
  3. User pays with a guarantor, no limit
  4. User pays with a guarantor, with a limit
note

Modes 2 and 3 are not compatible with the default storage access rules of ERC-4337 and require a whitelist for the guarantors.

Key Functions​

validatePaymasterUserOp​

function _validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) internal override returns (bytes memory context, uint256 validationResult)

Validates the paymaster data, calculates the required token amount, and transfers the tokens.

postOp​

function _postOp(
PostOpMode,
bytes calldata context,
uint256 actualGasCost,
uint256 actualUserOpFeePerGas
) internal override

Performs post-operation tasks, such as refunding excess tokens and attempting to pay back the guarantor if there is one.

updateMarkup​

function updateMarkup(uint32 _priceMarkup) external onlyOwner

Allows the contract owner to update the price markup percentage.

withdrawToken​

function withdrawToken(address to, uint256 amount) external onlyOwner

Allows the contract owner to withdraw a specified amount of tokens from the contract.

getPrice​

function getPrice() public view returns (uint192)

Fetches the latest token price using the configured oracles.

getHash​

function getHash(
PackedUserOperation calldata userOp,
uint48 validUntil,
uint48 validAfter,
uint256 tokenLimit
) public view returns (bytes32)

Hashes the user operation data for signature verification.

Events​

MarkupUpdated​

event MarkupUpdated(uint32 priceMarkup)

Emitted when the price markup is updated.

UserOperationSponsored​

event UserOperationSponsored(
bytes32 indexed userOpHash,
address indexed user,
address indexed guarantor,
uint256 tokenAmountPaid,
uint256 tokenPrice,
bool paidByGuarantor
)

Emitted when a user operation is sponsored by the paymaster.

Custom Errors​

The contract defines several custom errors for various failure conditions:

  • PaymasterDataModeInvalid()
  • PaymasterDataLengthInvalid()
  • TokenAmountTooHigh()
  • TokenLimitZero()
  • PriceMarkupTooHigh()
  • PriceMarkupTooLow()
  • OraclePriceStale()
  • OraclePriceNotPositive()
  • OracleDecimalsInvalid()